/**
 * 权限工具函数
 */

import { appStorage } from './storage';

/**
 * 权限检查器
 */
export class PermissionChecker {
  /**
   * 检查用户权限
   */
  static hasPermission(permission: string, userPermissions?: string[]): boolean {
    if (!permission) return true;
    
    const permissions = userPermissions || this.getUserPermissions();
    
    // 超级管理员拥有所有权限
    if (permissions.includes('*')) return true;
    
    // 检查具体权限
    return permissions.includes(permission);
  }

  /**
   * 检查多个权限（AND关系）
   */
  static hasAllPermissions(permissions: string[], userPermissions?: string[]): boolean {
    return permissions.every(permission => 
      this.hasPermission(permission, userPermissions)
    );
  }

  /**
   * 检查多个权限（OR关系）
   */
  static hasAnyPermission(permissions: string[], userPermissions?: string[]): boolean {
    return permissions.some(permission => 
      this.hasPermission(permission, userPermissions)
    );
  }

  /**
   * 检查角色权限
   */
  static hasRole(role: string, userRoles?: string[]): boolean {
    if (!role) return true;
    
    const roles = userRoles || this.getUserRoles();
    return roles.includes(role);
  }

  /**
   * 检查多个角色（AND关系）
   */
  static hasAllRoles(roles: string[], userRoles?: string[]): boolean {
    return roles.every(role => this.hasRole(role, userRoles));
  }

  /**
   * 检查多个角色（OR关系）
   */
  static hasAnyRole(roles: string[], userRoles?: string[]): boolean {
    return roles.some(role => this.hasRole(role, userRoles));
  }

  /**
   * 获取用户权限
   */
  private static getUserPermissions(): string[] {
    const user = appStorage.getUser();
    return user?.permissions || [];
  }

  /**
   * 获取用户角色
   */
  private static getUserRoles(): string[] {
    const user = appStorage.getUser();
    return user?.roles || [];
  }
}

/**
 * 平台权限检查器
 */
export class PlatformPermissionChecker {
  /**
   * 检查平台权限
   */
  static hasPermission(permission: string, userPermissions?: string[]): boolean {
    if (!permission) return true;
    
    const permissions = userPermissions || this.getPlatformUserPermissions();
    
    // 超级管理员拥有所有权限
    if (permissions.includes('platform:*')) return true;
    
    // 检查具体权限
    return permissions.includes(permission);
  }

  /**
   * 检查平台角色
   */
  static hasRole(role: string, userRoles?: string[]): boolean {
    if (!role) return true;
    
    const roles = userRoles || this.getPlatformUserRoles();
    return roles.includes(role);
  }

  /**
   * 检查租户访问权限
   */
  static canAccessTenant(tenantId: string): boolean {
    const user = appStorage.getPlatformUser();
    if (!user) return false;
    
    // 超级管理员可以访问所有租户
    if (user.isSuperAdmin) return true;
    
    // 空数组表示可以访问所有租户
    if (user.accessibleTenants?.length === 0) return true;
    
    // 检查是否在可访问列表中
    return user.accessibleTenants?.includes(tenantId) || false;
  }

  /**
   * 获取平台用户权限
   */
  private static getPlatformUserPermissions(): string[] {
    const user = appStorage.getPlatformUser();
    return user?.permissions || [];
  }

  /**
   * 获取平台用户角色
   */
  private static getPlatformUserRoles(): string[] {
    const user = appStorage.getPlatformUser();
    return user?.platformRoles || [];
  }
}

/**
 * 权限装饰器
 */
export function RequirePermission(permission: string) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    
    descriptor.value = function (...args: any[]) {
      if (!PermissionChecker.hasPermission(permission)) {
        throw new Error(`权限不足，需要权限: ${permission}`);
      }
      return originalMethod.apply(this, args);
    };
    
    return descriptor;
  };
}

/**
 * 角色装饰器
 */
export function RequireRole(role: string) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    
    descriptor.value = function (...args: any[]) {
      if (!PermissionChecker.hasRole(role)) {
        throw new Error(`权限不足，需要角色: ${role}`);
      }
      return originalMethod.apply(this, args);
    };
    
    return descriptor;
  };
}

/**
 * 权限工具函数
 */
export const permissionUtils = {
  /**
   * 格式化权限代码
   */
  formatPermissionCode: (module: string, action: string): string => {
    return `${module}:${action}`;
  },

  /**
   * 解析权限代码
   */
  parsePermissionCode: (code: string): { module: string; action: string } => {
    const [module, action] = code.split(':');
    return { module, action };
  },

  /**
   * 检查权限代码格式
   */
  isValidPermissionCode: (code: string): boolean => {
    return /^[a-zA-Z0-9_]+:[a-zA-Z0-9_*]+$/.test(code);
  },

  /**
   * 获取权限树
   */
  buildPermissionTree: (permissions: any[]): any[] => {
    const tree: any[] = [];
    const map = new Map();

    // 创建节点映射
    permissions.forEach(permission => {
      map.set(permission.id, { ...permission, children: [] });
    });

    // 构建树结构
    permissions.forEach(permission => {
      const node = map.get(permission.id);
      if (permission.parentId) {
        const parent = map.get(permission.parentId);
        if (parent) {
          parent.children.push(node);
        }
      } else {
        tree.push(node);
      }
    });

    return tree;
  },

  /**
   * 展开权限树
   */
  flattenPermissionTree: (tree: any[]): any[] => {
    const result: any[] = [];
    
    function traverse(nodes: any[]) {
      nodes.forEach(node => {
        result.push(node);
        if (node.children && node.children.length > 0) {
          traverse(node.children);
        }
      });
    }
    
    traverse(tree);
    return result;
  },

  /**
   * 获取权限路径
   */
  getPermissionPath: (permissions: any[], targetId: string): any[] => {
    const path: any[] = [];
    
    function findPath(nodes: any[], id: string): boolean {
      for (const node of nodes) {
        path.push(node);
        
        if (node.id === id) {
          return true;
        }
        
        if (node.children && findPath(node.children, id)) {
          return true;
        }
        
        path.pop();
      }
      
      return false;
    }
    
    const tree = permissionUtils.buildPermissionTree(permissions);
    findPath(tree, targetId);
    
    return path;
  },
}; 